//
//  RACViewController.m
//  Gunterapple
//
//  Created by 热带雨林 on 2021/7/24.
//  Copyright © 2021 热带雨林. All rights reserved.
//

#import "RACViewController.h"
#import <objc/runtime.h>
#import "Person.h"

@interface RACViewController ()

@end

@implementation RACViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
//    [self testI];
//    [self textII];
//    [self testIII];
//    [self testIIII];
//    [self testV];
//    [self testVI];
//    [self testVII];
//    [self testVIII];
//    [self testX];
//    [self testXI];
//    [self testXII];
//    [self testXIII];
//    [self testXV];
//    [self testXVI];
//    [self blockDemo3];
//    [self textDemoI];
//    [self testDemoII];
    [self showRealClass];
}
- (void)showRealClass{
//    UIButton *b1 = [UIButton new];
    UIView *v1 = [UIView new];
    
    object_setClass(v1, [Person class]);
    
//    NSLog(@"HH");

}

#pragma mark - 冷信号
- (void)testI{
    /*
     1.创建信号createSignal 中创建DynamicSignal 信号 并将didsubscribe 通过copy的形式保存起来
     2.订阅信号 signal 通过调用subscriberNext 创建订阅者 subscriber 并将nextBlock保存在订阅者中，最后将订阅者保存起来
     3. 将nextBlock 和订阅者都保存起来之后，信号调用保存在信号中didSubscribe 注意：这时又回到了创建信号的block中，使用保存起来的订阅者 发送信号
     4.sendNext 中就是调用订阅者中保存的nextBlock 注意：最终要执行的就是订阅信号的block的回调
     
     didsubscribe是保存在信号中的
     signal创建完订阅者并将nextBlock保存在订阅者中  之后signal调用保存在信号中的didsubscribe
     调用didsubscribe的目的就是回到创建signal的block中使用订阅者发送信号
     发送信号也就是调用保存在订阅者中的nextBlock
     
     */
    //创建信号
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        
        //参数是一个函数
        //发送信号
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@(2)];
        [subscriber sendNext:@(3)];
        [subscriber sendError:nil];
        
        //信号发送完毕
        [subscriber sendCompleted];
        
        //返回值还是一个函数
        //返回信号
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"this is a RAC!");
        }];
        
    }];
    
    //将是函数的参数传到另个函数中
    //订阅信号
    //目的就是执行订阅者中的nextBlock
    [signalA subscribeNext:^(id  _Nullable x) {
        NSLog(@"signalA value is %@----",x);
    }];
    
}

#pragma mark - 热信号
-(void)textII{
    //创建信号  热信号创建时没有block的回调
    RACSubject *subject =  [RACSubject subject];
    
    //订阅信号  创建订阅者 将nextBlock保存在订阅者中
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"RAC value is %@",x);
    }];
    
    //发送信号  遍历保存的订阅者 逐个调用订阅者中的nextBlock
    [subject sendNext:@"1"];
    [subject sendError:nil];
    
    //结束订阅
    [subject sendCompleted];
    
}

/*
 常用高阶函数
 */

#pragma  mark - bind 绑定 类似于消息转发
-(void)testIII{
    //创建信号
//    RACSubject *subject = [RACSubject subject];
//
//    //绑定新信号
//    RACSignal *signal = [subject bind:^RACSignalBindBlock _Nonnull {
//        return ^RACSignal*(id value,BOOL *stop){
//            return[RACSignal return:value];
//        };
//    }];
//    //signal 订阅信号
//    [signal subscribeNext:^(id  _Nullable x) {
//        NSLog(@"bind x is [%@]",x);
//    }];
//
//    //subject发送信号
//    [subject sendNext:@"123"];
    
    
    RACSubject *subject = [RACSubject subject];
    
    RACSignal *signal = [subject bind:^RACSignalBindBlock _Nonnull{
        return ^RACSignal * (id value, BOOL *stop){
            return [RACSignal return:value];
        };
    }];
    
    //注意：bind之后，发送消息不再是subject而是由signal发送消息
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"bind value is %@",x);
    }];
    
    [subject sendNext:@"123"];
}


#pragma mark - concat 合并
- (void)testIIII{
    
    RACSubject *subject = [RACSubject subject];
    RACSubject *subject2 = [RACSubject subject];
    
    RACSignal *signal = [subject concat:subject2];
    //订阅信号
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"concat value is %@",x);
    }];
    
    //发送信号
    [subject sendNext:@"123"];
    //类似于串行 第一个信号发送完毕之后必须要发送完成，第二个信号才能发送
    [subject sendCompleted];
    
    [subject2 sendNext:@"AAA"];
    
    /*
     2021-12-05 22:49:32.314623+0800 Gunterapple[12523:3698237] concat value is 123
     2021-12-05 22:49:32.314870+0800 Gunterapple[12523:3698237] concat value is AAA
     */
    
}

#pragma mark - merge 按顺序合并
- (void)testV{
    RACSubject *subject = [RACSubject subject];
    RACSubject *subject2 = [RACSubject subject];
    
    RACSignal *signal = [subject merge:subject2];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"merge value is %@",x);
    }];
    
    //merge 是不需要添加complete，直接就是按照顺序合并
    [subject sendNext:@"123"];
    [subject2 sendNext:@"AAA"];
    
    
    /*
     merge value is 123
     merge value is AAA
     */
}

#pragma mark - flattenMap 映射
- (void)testVI{
    
    RACSubject *subject = [RACSubject subject];
    
    //绑定信号并返回映射后的值
    RACSignal *signal = [subject flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
        //value 修改
        value = [NSString stringWithFormat:@"flattenMap映射之后的值为%@",value];
        return [RACSignal return:value];
    }];
    
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"flattenMap value is [%@]",x);
    }];
    
    
    [subject sendNext:@"123"];
    
}

#pragma mark - map
- (void)testVII{
    RACSubject *subject = [RACSubject subject];
    
    //直接将返回的值修改为str
    RACSignal *signal = [subject map:^id _Nullable(id  _Nullable value) {
        NSString *str = [NSString stringWithFormat:@"map之后的新值%@",value];
        return  str;
    }];
    
    //订阅中的就是需要打印出来的内容
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"map value is %@",x);
    }];
    
    [subject sendNext:@"123"];
}

#pragma mark - filter 过滤
- (void)testVIII{
    
    RACSubject *subject = [RACSubject subject];
    
    RACSignal *signal = [subject filter:^BOOL(id  _Nullable value) {
        //此处是判断条件
        NSString *str = value;
        if([str containsString:@"123"])
            return  YES;
        else
            return NO;
//        if([str hasPrefix:@"123"])
//            return YES;
//        else
//            return NO;
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"filter value is %@",x);
    }];
    
    [subject sendNext:@"ABC123"];
    [subject sendNext:@"abcdefg"];
}

#pragma mark - ignore 忽略
/*
 根据信号内容进行忽略
 */
- (void)testX{
    
    RACSubject *subject = [RACSubject subject];

    //注意：subject调用ignore方法之后返回的是一个信号 需要使用信号进行接收
    RACSignal *signal = [subject ignore:@"ABC"];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"忽略之后的信号值是:%@",x);
    }];
    
    [subject sendNext:@"ABC"];
    [subject sendNext:@"123"];
    [subject sendNext:@"abc"];
    [subject sendCompleted];
    
    /*
     2021-12-05 22:57:25.069463+0800 Gunterapple[12549:3702460] 忽略之后的信号值是:123
     2021-12-05 22:57:25.069831+0800 Gunterapple[12549:3702460] 忽略之后的信号值是:abc
     */

}

#pragma mark - then
/*
 根据信号进行忽略
 */
- (void)testXI{
    
    RACSubject *subject = [RACSubject subject];
    RACSubject *subject2 = [RACSubject subject];
    
    //忽略掉subject的信号
    RACSignal *signal = [subject then:^RACSignal * _Nonnull{
        //忽略的就是subject的信号，注意，谁后跟着sendCompleted 谁就会被忽略
        return subject;
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"then value is %@",x);
    }];
    
    [subject sendNext:@"123"];
    [subject sendNext:@"abc"];
    [subject sendCompleted];
    
    [subject2 sendNext:@"ABC"];
    [subject2 sendNext:@"hee"];
//    [subject sendCompleted];
}

#pragma mark - take
- (void)testXII{
    RACSubject *subject = [RACSubject subject];
    
    //获取1-3的信号，其余忽略
    RACSignal *signal = [subject take:3];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"take x is %@",x);
    }];
    
    [subject sendNext:@"1"];
    [subject sendNext:@"2"];
    [subject sendNext:@"3"];
    [subject sendNext:@"4"];
    [subject sendNext:@"5"];
    [subject sendNext:@"6"];
}

#pragma mark - skip
- (void)testXIII{
    RACSubject *subject = [RACSubject subject];
    
    //跳过1-3的信号，获取剩余的信号
    RACSignal *signal = [subject skip:3];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"skip x is %@",x);
    }];
    
    [subject sendNext:@"1"];
    [subject sendNext:@"2"];
    [subject sendNext:@"3"];
    [subject sendNext:@"4"];
    [subject sendNext:@"5"];
    [subject sendNext:@"6"];
}

#pragma mark - switchTolatest //此处算是一个属性
- (void)testXV{
    //创建信号
    RACSubject *subject = [RACSubject subject];
    //创建内部信号  用于subject的内部信号
    RACSubject *innertSub = [RACSubject subject];
    //同上
    RACSubject *innerSub2 = [RACSubject subject];
    
    //通过属性的形式，获得最新的信号中的信号的信息
    [subject.switchToLatest subscribeNext:^(id  _Nullable x) {
        NSLog(@"switchToLatest value is %@",x);
    }];
    
    [subject sendNext:innertSub];
    
    [subject sendNext:innerSub2];
    
    [innertSub sendNext:@"nihao"];
    
    [innerSub2 sendNext:@"123"]; //最终结果
    
}

#pragma mark - distinctUntilChanged
/*
 作用: 忽略重复的信号
 例：执行后，忽略了重复的1
 
 简单理解就是去除重复的信号
 */
- (void)testXVI{
    
    RACSubject *subject = [RACSubject subject];
    
    [subject.distinctUntilChanged subscribeNext:^(id  _Nullable x) {
        NSLog(@"去除重复之后的信号结果是:%@",x);
    }];
    
    //类似的结构都是重复
    [subject sendNext:@"11"];
    [subject sendNext:@"1"];
    [subject sendNext:@"11"];
    
    [subject sendNext:@"123"];
    //大小写也没有办法区分
    [subject sendNext:@"ABC"];
    [subject sendNext:@"abc"];
    
}

//对于可变对象 block是深拷贝 还是浅拷贝
- (void)blockDemo3
{
//注意：strM已经是堆区中的值了，
    NSMutableString *strM= [NSMutableString stringWithString:@"hello"];
    
    /*
     block的内部捕获了可变对象，添加元素，相当于是要修改可变对象的值，那么肯定就是浅copy了，
     因为如果是深copy的话，会创建出一个新的对像开辟新的内存，与原来的对像是没有关系的，无论怎么改原来的对象都不会变，
     新创建的对象与原来的对象是没有关系的，但是浅copy是增加了对像和指针，指向了原先的内存，改的是原先对象内存中的值
     */
    void (^block)(void) = ^ {
        //此处的修改就是值拷贝，也就是浅拷贝，但是指针指的是同一块堆区的内存，修改的也是堆区内存中的值
        //如果使用__block进行修饰，那就是指针拷贝，那就会生成一个全新的对象，修改的也是全新的对象，与原对象没有关系了
        [strM appendString:@"hehe"];
    };
    
    block();
    
    NSLog(@"%@",strM);
    //hellohehe
}
- (void)textDemoI{
    //RACReplaySubject是 RACSubject的子类
    RACReplaySubject *replayS = [RACReplaySubject subject];
    
    [replayS sendNext:@"nihao"];
    [replayS sendNext:@"hehe"];
    
    [replayS subscribeNext:^(id  _Nullable x) {
        NSLog(@"第一次发消息：%@",x);
    }];
    [replayS subscribeNext:^(id  _Nullable x) {
        NSLog(@"第二次发消息：%@",x);
    }];
    
    /*
     第一次发消息：nihao
     2021-12-05 22:41:34.348863+0800 Gunterapple[12507:3695369] 第一次发消息：hehe
     2021-12-05 22:41:34.349079+0800 Gunterapple[12507:3695369] 第二次发消息：nihao
     2021-12-05 22:41:34.349192+0800 Gunterapple[12507:3695369] 第二次发消息：hehe
     */
}
#pragma mark - RAC 操作 集合
//快速遍历字典
- (void)testDemoII{
    NSDictionary *dic = @{@"account":@"flower",@"age": @"18"};
    [dic.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        RACTupleUnpack(NSString *key,NSString *value) = x;
        NSLog(@"%@ %@",key,value);
    }];
    /*
     account flower
     age 18
     */
}

//


/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/



@end
